package cn.maihe.elg.operation.supports.invoice.nuonuo;

import cn.maihe.elg.operation.centers.supports.CenterInterfaceService;
import cn.maihe.elg.operation.centers.supports.CenterInterfaceServiceFactory;
import cn.maihe.elg.operation.model.dto.InnerBaseResp;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.InvoiceReversalFlag;
import cn.maihe.elg.operation.model.enums.InvoiceStatusEnum;
import cn.maihe.elg.operation.repository.entity.InvoiceInfoDO;
import cn.maihe.elg.operation.repository.entity.SellerInfoDO;
import cn.maihe.elg.operation.repository.entity.SellerInfoDOCondition;
import cn.maihe.elg.operation.service.business.ExchangeCenterService;
import cn.maihe.elg.operation.service.invoice.InvoiceInfoService;
import cn.maihe.elg.operation.service.invoice.SellerInfoService;
import cn.maihe.elg.operation.supports.invoice.nuonuo.dto.*;
import cn.maihe.elg.operation.utils.ElgLogger;
import cn.maihe.elg.operation.utils.IdGenerate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import nuonuo.open.sdk.NNOpenSDK;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author caixh
 * @Date 2021/4/30.
 */
@Component
@Slf4j
public class InvoiceHelper {
    @Resource
    private InvoiceNuonuoConfig invoiceNuonuoConfig;
    @Resource
    private SellerInfoService sellerInfoService;
    @Resource
    private InvoiceInfoService invoiceInfoService;
    @Resource
    private InvoiceDownLoadHelper invoiceDownLoadHelper;
    @Resource
    private ExchangeCenterService exchangeCenterService;

    public String requestBillingNew(String acceptOrderNo, InvoiceInfoDO invoiceInfoDO) {
        return requestBillingNew(acceptOrderNo,invoiceInfoDO,null);
    }

    /**
     * 开票请求
     *
     * @param acceptOrderNo
     * @param invoiceInfoDO
     * @return String 开票受理成功返回 invoiceSerialNum，false开票失败，可重新开票
     */
    public String requestBillingNew(String acceptOrderNo, InvoiceInfoDO invoiceInfoDO, String projectName) {
        // API方法名
        String method = "nuonuo.OpeMplatform.requestBillingNew";
        NNOpenSDK sdk = NNOpenSDK.getIntance();

        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(invoiceInfoDO.getOrgId()).build());

        OrderDTO orderDTO = new OrderDTO(invoiceInfoDO, sellerInfoDO, invoiceNuonuoConfig.getCallbackUrl(),false,invoiceNuonuoConfig.getExtensionNumber(), projectName);

        JSONObject content = new JSONObject();
        content.put("order", orderDTO);


        ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> 开票请求报文：{}", acceptOrderNo, content));
        // 唯一标识，32位随机码，无需修改，保持默认即可
        String senid = IdGenerate.get32UUID();
        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                sellerInfoDO.getToken(), invoiceInfoDO.getSellerCreditCode(), method, content.toJSONString());

        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << 开票请求受理结果：{}", acceptOrderNo, result));
        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.containsKey("code")) {
            String code = resultJson.getString("code");
            String describe = resultJson.getString("describe");
            if (ReturnCode.E0000.name().equals(code)) {
                String invoiceSerialNum = resultJson.getJSONObject("result").getString("invoiceSerialNum");
                return invoiceSerialNum;
            } else  if(!"040102".equals(code)){
                //异常
                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 开票请求受理失败[{}:{}]", acceptOrderNo, code, describe));
                throw new RuntimeException(String.format("开票受理失败[%s,%s]", code, describe));
            }
            return null;
        } else {
            //异常
            ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 开票请求处理失败：响应报文不存在code字段", acceptOrderNo));
            throw new RuntimeException(String.format("开票受理失败：响应报文不存在code字段"));
        }
    }

    /**
     * 开票结果查询
     *
     * @param invoiceInfoDO
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
    public InvoiceInfoDO queryInvoiceResultAndDownload(InvoiceInfoDO invoiceInfoDO) {

        if(invoiceInfoDO.getInvoiceType() == 3){
            return queryConfirm(invoiceInfoDO);
        }

        String method = "nuonuo.OpeMplatform.queryInvoiceResult";
        NNOpenSDK sdk = NNOpenSDK.getIntance();
        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(invoiceInfoDO.getOrgId()).build());
        String acceptOrderNo = invoiceInfoDO.getAcceptOrderNos();

        List<String> orders = new ArrayList<>();
        orders.add(invoiceInfoDO.getId().toString());

        QueryDTO queryDTO = new QueryDTO();
        queryDTO.setOrderNos(orders);
        if (StringUtils.isNotBlank(invoiceInfoDO.getSerialNo())) {
            List<String> serialNos = new ArrayList<>();
            serialNos.add(invoiceInfoDO.getSerialNo());
            queryDTO.setSerialNos(serialNos);
        }

        String appendName = (invoiceInfoDO.getInvoiceType() != null && invoiceInfoDO.getInvoiceType() == 2) ? "红票" : "蓝票";

        ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> "+appendName+"开票结果查询请求报文：{}", acceptOrderNo, JSONObject.toJSONString(queryDTO)));
        // 唯一标识，32位随机码，无需修改，保持默认即可
        String senid = IdGenerate.get32UUID();
        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                sellerInfoDO.getToken(), invoiceInfoDO.getSellerCreditCode(), method, JSONObject.toJSONString(queryDTO));
        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << "+appendName+"开票结果查询响应报文：{}", acceptOrderNo, result));

        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.containsKey("code")) {
            String code = resultJson.getString("code");
            String describe = resultJson.getString("describe");
            if (ReturnCode.E0000.name().equals(code)) {
                //判断开票状态
                List<InvoiceInfoDTO> invoiceInfoDTOs = resultJson.getJSONArray("result").toJavaList(InvoiceInfoDTO.class);
                InvoiceInfoDTO dto = invoiceInfoDTOs.get(0);
                String status = dto.getStatus();
                String statusMsg = dto.getStatusMsg();
                String failCause = dto.getFailCause();
                if ("2".equals(dto.getStatus())) {
                    //完成
                    invoiceInfoDO.setStatus(InvoiceStatusEnum.TODOWNLOAD.getValue());
                    invoiceInfoDO.setPdfUrl(dto.getPdfUrl());
                    invoiceInfoDO.setInvoiceNo(dto.getInvoiceNo());
                    invoiceInfoDO.setInvoiceCode(dto.getInvoiceCode());
                    try {
                        ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> "+appendName+"发票下载请求报文：{}", acceptOrderNo, JSONObject.toJSONString(queryDTO)));
                        Path invoicePdf = invoiceDownLoadHelper.downloadInvoice(dto.getPdfUrl());
                        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << "+appendName+"发票下载成功：{}", acceptOrderNo, invoicePdf.toAbsolutePath().toString()));
                        invoiceDownLoadHelper.savePdfAndUpdateInvoice(invoicePdf, invoiceInfoDO);
                        invoiceInfoDO.setStatus(InvoiceStatusEnum.INVOICED.getValue());
                        invoiceInfoDO.setRemark(appendName+"开票&下载完成");
                    } catch (Exception e) {
                        invoiceInfoDO.setRemark(appendName+"已开票下载失败:" + e.getMessage());
                        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << "+appendName+"发票下载失败：{}", acceptOrderNo, e.getMessage(), e));
                    } finally {
                        invoiceInfoService.updateById(invoiceInfoDO);
                    }
                } else if ("20".equals(status) || "21".equals(status)) {
                    //开票中重复查询，每次间隔3s :待优化
                    try {
                        TimeUnit.SECONDS.sleep(3);
                        int curQueryTimes = invoiceInfoDO.getQueryTimes() == null ? 1 : invoiceInfoDO.getQueryTimes() + 1;
                        invoiceInfoDO.setQueryTimes(curQueryTimes);
                        if (curQueryTimes > 5) {
                            ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询[超最大次数:{}]终止查询处理，开票结果状态[{}:{}:{}]", acceptOrderNo, curQueryTimes, status, statusMsg, failCause));
                            invoiceInfoDO.setStatus(InvoiceStatusEnum.PROSESS.getValue());
                            invoiceInfoDO.setRemark(appendName+"开票中,开票结果查询[超最大次数:" + curQueryTimes + "]终止查询处理");
                            invoiceInfoService.updateById(invoiceInfoDO);
                            //
                        } else {
                            //递归查询
                            this.queryInvoiceResultAndDownload(invoiceInfoDO);
                        }
                    } catch (InterruptedException e) {
                        ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询休眠异常中断：{}", acceptOrderNo, e.getMessage(), e));
                    }
                } else if ("22".equals(dto.getStatus()) || "24".equals(dto.getStatus())) {
                    ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询返回开票失败[{}:{}:{}]", acceptOrderNo, status, statusMsg, failCause));
                    throw new RuntimeException(failCause);
//                    if("22".equals(dto.getStatus()) && failCause.startsWith("[9999]本次操作需登录电子发票服务平台") ){
//                        throw new RuntimeException("当前开票状态为开票失败,请先使用短信验证码登录，在发票后台重开后进行开函重试");
//                    }
//
//                    invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
//                    invoiceInfoDO.setRemark(String.format(appendName+"开票结果查询返回开票失败[%s:%s:%s]", status, statusMsg, failCause));
//                    invoiceInfoService.updateById(invoiceInfoDO);
//                    invoiceInfoService.failHandle(invoiceInfoDO);
                } else {
                    ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询返回开票状态未定义暂不处理[{}:{}:{}]", acceptOrderNo, status, statusMsg, failCause));
                }
            } else  if(!"040102".equals(code)){
                //异常：做开票失败处理
                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询失败[{}:{}]", acceptOrderNo, code, describe));
                invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
                invoiceInfoDO.setRemark(String.format(appendName+"开票结果查询返回异常[%s:%s]，做开票失败处理", code, describe));
                invoiceInfoService.updateById(invoiceInfoDO);
                invoiceInfoService.failHandle(invoiceInfoDO);
            }
        } else {
            //异常
            ElgLogger.error(log, l -> l.error("acceptOrderNo={} << "+appendName+"开票结果查询处理失败：响应报文不存在code字段", acceptOrderNo));
        }
        return invoiceInfoDO;
    }

    public InvoiceInfoDO queryConfirm(InvoiceInfoDO invoiceInfoDO){
        String method = "nuonuo.OpeMplatform.queryInvoiceRedConfirm";
        NNOpenSDK sdk = NNOpenSDK.getIntance();
        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(invoiceInfoDO.getOrgId()).build());
        String acceptOrderNo = invoiceInfoDO.getAcceptOrderNos();

        RedConfirmQueryDTO queryDTO = new RedConfirmQueryDTO();
        queryDTO.setBillId(invoiceInfoDO.getId().toString());

        ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> 红票确认单结果查询请求报文：{}", invoiceInfoDO.getAcceptOrderNos(), JSONObject.toJSONString(queryDTO)));
        // 唯一标识，32位随机码，无需修改，保持默认即可
        String senid = IdGenerate.get32UUID();
        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                sellerInfoDO.getToken(), invoiceInfoDO.getSellerCreditCode(), method, JSONObject.toJSONString(queryDTO));
        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << 红票确认单结果查询请求报文：{}", acceptOrderNo, result));

        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.containsKey("code")){

            String code = resultJson.getString("code");
            String describe = resultJson.getString("describe");
            if (ReturnCode.E0000.name().equals(code)) {
                resultJson.getJSONObject("result").getJSONArray("list").forEach(obj -> {
                    JSONObject confirmRed = (JSONObject) obj;
                    String billStatus = confirmRed.getString("billStatus");
                    String openStatus = confirmRed.getString("openStatus");
                    if(billStatus.equals("01")||billStatus.equals("04")){
                        //成功
                        if("0".equals(openStatus)){
                            String method1 = "nuonuo.OpeMplatform.fastInvoiceRed";
                            InvoiceInfoDO reversalInvoiceInfo = new InvoiceInfoDO();
                            BeanUtils.copyProperties(invoiceInfoDO, reversalInvoiceInfo);
                            reversalInvoiceInfo.setId(invoiceInfoDO.getInvoiceReversalId());
                            //开票类型红票
                            reversalInvoiceInfo.setInvoiceType(2);
                            reversalInvoiceInfo.setInvoiceReversalFlag(InvoiceReversalFlag.UNDO.getFlag());
                            reversalInvoiceInfo.setRemark(null);
                            reversalInvoiceInfo.setPdfUrl(null);
                            reversalInvoiceInfo.setInvoiceImg(null);
                            reversalInvoiceInfo.setInvoiceReversalId(null);

                            reversalInvoiceInfo.setGmtCreate(new Date());
                            reversalInvoiceInfo.setGmtModified(new Date());

                            RedOrderDTO redOrderDTO = new RedOrderDTO();
                            redOrderDTO.setOrderNo(reversalInvoiceInfo.getId().toString());
//                            redOrderDTO.setExtensionNumber("");
//                            redOrderDTO.setClerkId("");
//                            redOrderDTO.setDeptId("");
//                            redOrderDTO.setOrderTime("");
                            redOrderDTO.setTaxNum(sellerInfoDO.getSellerCreditCode());
                            redOrderDTO.setInvoiceCode(invoiceInfoDO.getInvoiceCode());
                            redOrderDTO.setInvoiceNumber(invoiceInfoDO.getInvoiceNo());
//                            redOrderDTO.setInvoiceId("");
                            redOrderDTO.setBillNo(confirmRed.getString("billNo"));
                            redOrderDTO.setBillUuid(confirmRed.getString("billUuid"));
//                            redOrderDTO.setInvoiceLine();
                            redOrderDTO.setCallBackUrl(invoiceNuonuoConfig.getCallbackUrl());

                            ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> 发票开票请求报文：{}", acceptOrderNo, JSONObject.toJSONString(redOrderDTO)));
                            // 唯一标识，32位随机码，无需修改，保持默认即可
                            String senid1 = IdGenerate.get32UUID();
                            String result1 = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid1,
                                    invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                                    sellerInfoDO.getToken(), reversalInvoiceInfo.getSellerCreditCode(), method1, JSONObject.toJSONString(redOrderDTO));

                            ElgLogger.info(log, l -> l.info("acceptOrderNo={} << 发票开票请求受理结果：{}", acceptOrderNo, result1));

                            JSONObject resultJson1 = JSONObject.parseObject(result1);
                            if (resultJson1.containsKey("code")) {
                                String code1 = resultJson1.getString("code");
                                String describe1 = resultJson1.getString("describe");
                                if (ReturnCode.E0000.name().equals(code1)) {
                                    String invoiceSerialNum = resultJson1.getJSONObject("result").getString("invoiceSerialNum");
                                    reversalInvoiceInfo.setStatus(InvoiceStatusEnum.PROSESS.getValue());
                                    reversalInvoiceInfo.setSerialNo(invoiceSerialNum);
                                    reversalInvoiceInfo.setInvoiceMode(1);

                                    invoiceInfoService.insert(reversalInvoiceInfo);
                                    InvoiceInfoDO updateInvoiceInfo = InvoiceInfoDO.builder().id(invoiceInfoDO.getId())
                                            .status(InvoiceStatusEnum.INVOICED.getValue()).build();
                                    invoiceInfoService.updateById(updateInvoiceInfo);
                                } else {
                                    //异常
                                    ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 发票冲红开票请求受理失败[{}:{}]", acceptOrderNo, code, describe));
                                    throw new RuntimeException(String.format("发票冲红开票受理失败[%s,%s]", code, describe));
                                }
                            } else {
                                //异常
                                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 发票冲红开票请求处理失败：响应报文不存在code字段", acceptOrderNo));
                                throw new RuntimeException(String.format("发票冲红开票受理失败：响应报文不存在code字段"));
                            }
                        }else if("1".equals(openStatus)){
                            InvoiceInfoDO redInvoice = invoiceInfoService.selectById(invoiceInfoDO.getInvoiceReversalId());
                            if(redInvoice == null){
                                InvoiceInfoDO reversalInvoiceInfo = new InvoiceInfoDO();
                                BeanUtils.copyProperties(invoiceInfoDO, reversalInvoiceInfo);
                                reversalInvoiceInfo.setId(invoiceInfoDO.getInvoiceReversalId());
                                //开票类型红票
                                reversalInvoiceInfo.setInvoiceType(2);
                                reversalInvoiceInfo.setInvoiceReversalFlag(InvoiceReversalFlag.UNDO.getFlag());
                                reversalInvoiceInfo.setRemark(null);
                                reversalInvoiceInfo.setPdfUrl(null);
                                reversalInvoiceInfo.setInvoiceImg(null);
                                reversalInvoiceInfo.setInvoiceReversalId(null);

                                reversalInvoiceInfo.setGmtCreate(new Date());
                                reversalInvoiceInfo.setGmtModified(new Date());
                                reversalInvoiceInfo.setStatus(InvoiceStatusEnum.PROSESS.getValue());
                                reversalInvoiceInfo.setSerialNo(null);
                                reversalInvoiceInfo.setInvoiceMode(1);

                                invoiceInfoService.insert(reversalInvoiceInfo);
                            }

                            InvoiceInfoDO updateInvoiceInfo = InvoiceInfoDO.builder().id(invoiceInfoDO.getId())
                                    .status(InvoiceStatusEnum.INVOICED.getValue()).build();
                            invoiceInfoService.updateById(updateInvoiceInfo);
                        }

                    }else if(billStatus.equals("05")||billStatus.equals("07")||billStatus.equals("08")
                            ||billStatus.equals("09")||billStatus.equals("06")){
                        //失败
                        InvoiceInfoDO updateInvoiceInfo = InvoiceInfoDO.builder().id(invoiceInfoDO.getId())
                                .status(InvoiceStatusEnum.FAIL.getValue()).build();
                        invoiceInfoService.updateById(updateInvoiceInfo);

                    }
                });
            }else  if(!"040102".equals(code)){
                //异常：做开票失败处理
                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 红票确认单结果查询请求报文[{}:{}]", acceptOrderNo, code, describe));
                invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
                invoiceInfoDO.setRemark(String.format("红票确认单结果查询返回异常[%s:%s]，做开票失败处理", code, describe));
                invoiceInfoService.updateById(invoiceInfoDO);
                invoiceInfoService.failHandle(invoiceInfoDO);
            }
        }else {
            //异常
            ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 红票确认单结果查询请求报文：响应报文不存在code字段", acceptOrderNo));
        }
        return invoiceInfoDO;

    }
//
//    public String queryInvoice(InvoiceInfoDO invoiceInfoDO) {
//        String method = "nuonuo.ElectronInvoice.queryInvoiceResult";
//        NNOpenSDK sdk = NNOpenSDK.getIntance();
//        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(invoiceInfoDO.getOrgId()).build());
//
//        List<String> orders = new ArrayList<>();
//        orders.add(invoiceInfoDO.getId().toString());
//        QueryDTO queryDTO = new QueryDTO();
//        queryDTO.setOrderNos(orders);
//        String senid = IdGenerate.get32UUID();// 唯一标识，32位随机码，无需修改，保持默认即可
//        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
//                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
//                sellerInfoDO.getToken(), invoiceInfoDO.getSellerCreditCode(), method, JSONObject.toJSONString(queryDTO));
//        ElgLogger.debug(log, l -> l.debug("开票查询结果：{}", result));
//        JSONObject resultJson = JSONObject.parseObject(result);
//        if (resultJson.containsKey("code")) {
//            String code = resultJson.getString("code");
//            if (ReturnCode.E0000.name().equals(code)) {
//                //判断开票状态
//                List<InvoiceInfoDTO> invoiceInfoDTOs = resultJson.getJSONArray("result").toJavaList(InvoiceInfoDTO.class);
//                InvoiceInfoDTO dto = invoiceInfoDTOs.get(0);
//                if ("2".equals(dto.getStatus())) {
//                    return dto.getInvoiceNo();
//                }
//            } else {
//                throw new RuntimeException("开票异常:" + result);
//            }
//        }
//        return "";
//    }
//
//    /**
//     * 开票结果查询
//     *
//     * @param invoiceInfoDO
//     */
//    public void queryInvoiceResult(InvoiceInfoDO invoiceInfoDO) {
//        String method = "nuonuo.ElectronInvoice.queryInvoiceResult";
//        NNOpenSDK sdk = NNOpenSDK.getIntance();
//        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(invoiceInfoDO.getOrgId()).build());
//
//        List<String> orders = new ArrayList<>();
//        orders.add(invoiceInfoDO.getId().toString());
//        QueryDTO queryDTO = new QueryDTO();
//        queryDTO.setOrderNos(orders);
//
//        String senid = IdGenerate.get32UUID();// 唯一标识，32位随机码，无需修改，保持默认即可
//        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
//                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
//                sellerInfoDO.getToken(), invoiceInfoDO.getSellerCreditCode(), method, JSONObject.toJSONString(queryDTO));
//        ElgLogger.debug(log, l -> l.debug("开票查询结果：{}", result));
//        JSONObject resultJson = JSONObject.parseObject(result);
//        if (resultJson.containsKey("code")) {
//            String code = resultJson.getString("code");
//            if (ReturnCode.E0000.name().equals(code)) {
//                //判断开票状态
//                List<InvoiceInfoDTO> invoiceInfoDTOs = resultJson.getJSONArray("result").toJavaList(InvoiceInfoDTO.class);
//                InvoiceInfoDTO dto = invoiceInfoDTOs.get(0);
//                if ("2".equals(dto.getStatus())) {
//                    //完成
//                    invoiceInfoDO.setStatus(InvoiceStatusEnum.TODOWNLOAD.getValue());
//                    invoiceInfoDO.setInvoiceImg(dto.getPdfUrl());
//                    invoiceInfoDO.setInvoiceNo(dto.getInvoiceNo());
//                    invoiceInfoDO.setInvoiceCode(dto.getInvoiceCode());
//                } else if ("22".equals(dto.getStatus()) || "24".equals(dto.getStatus())) {
//                    invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
//                }
//            } else {
//                //异常
//                invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
//                ElgLogger.error(log, l -> l.error("开票查询异常:{}", result));
//            }
//        } else {
//            //异常
//            invoiceInfoDO.setStatus(InvoiceStatusEnum.FAIL.getValue());
//            ElgLogger.error(log, l -> l.error("开票查询异常:{}", result));
//        }
//        invoiceInfoService.updateById(invoiceInfoDO);
//        if (invoiceInfoDO.getStatus() == InvoiceStatusEnum.TODOWNLOAD.getValue()) {
//            //todo 异步下载
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        invoiceDownLoadHelper.downloadInvoice(invoiceInfoDO);
//                    } catch (IOException e) {
//                        ElgLogger.error(log, l -> l.error("发票下载失败"));
//                    }
//                }
//            }).start();
//        }
//    }

    /**
     * 认证地址获取
     *
     * @return
     */
    public String getAUthUrl() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(invoiceNuonuoConfig.getAuthorizeUrl());
        stringBuilder.append("appKey=" + invoiceNuonuoConfig.getAppKey());
        stringBuilder.append("&response_type=code");
        stringBuilder.append("&redirect_uri=" + invoiceNuonuoConfig.getRedirectUri());
        stringBuilder.append("&state=999");

        return stringBuilder.toString();
    }

    /**
     * 原发票冲红操作
     *
     * @param invoiceInfoDO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void doInvoiceReversal(InvoiceInfoDO invoiceInfoDO) {
        if(invoiceInfoDO==null || InvoiceStatusEnum.INVOICED.getValue()!=invoiceInfoDO.getStatus()){
            throw new RuntimeException("原发票记录为空或原发票状态不为已开票,不能发起发票冲红操作");
        }
        InvoiceReversalFlag reversalFlag =  InvoiceReversalFlag.resolve(invoiceInfoDO.getInvoiceReversalFlag());
        if(reversalFlag==null){
            throw new RuntimeException("原发票冲红标记位无法识别["+invoiceInfoDO.getInvoiceReversalFlag()+"]");
        }
        if(reversalFlag!=InvoiceReversalFlag.WAITING &&reversalFlag!=InvoiceReversalFlag.FAILURE){
            throw new RuntimeException("原发票冲红标记为[" + reversalFlag.getFlag() + ":" + reversalFlag.getDesc() + "],不能发起冲红操作");
        }
        // API方法名
//        String method = "nuonuo.OpeMplatform.fastInvoiceRed";
        String method = "nuonuo.OpeMplatform.saveInvoiceRedConfirm";
        NNOpenSDK sdk = NNOpenSDK.getIntance();
        InvoiceInfoDO reversalInvoiceInfo = new InvoiceInfoDO();
        BeanUtils.copyProperties(invoiceInfoDO, reversalInvoiceInfo);
        reversalInvoiceInfo.setId(IdGenerate.getId());
        //开票类型红票
        reversalInvoiceInfo.setInvoiceType(3);
        reversalInvoiceInfo.setInvoiceReversalFlag(InvoiceReversalFlag.UNDO.getFlag());
        reversalInvoiceInfo.setRemark(null);
        reversalInvoiceInfo.setPdfUrl(null);
        reversalInvoiceInfo.setInvoiceImg(null);
        reversalInvoiceInfo.setInvoiceReversalId(IdGenerate.getId());

        reversalInvoiceInfo.setGmtCreate(new Date());
        reversalInvoiceInfo.setGmtModified(new Date());


        SellerInfoDO sellerInfoDO = sellerInfoService.selectOne(SellerInfoDOCondition.builder().andOrgIdEq(reversalInvoiceInfo.getOrgId()).build());

        RedOrderReqDTO redOrderDTO = new RedOrderReqDTO();
        redOrderDTO.setBillId(reversalInvoiceInfo.getId().toString());
        redOrderDTO.setBlueInvoiceLine("pc");
        redOrderDTO.setApplySource("0");
        redOrderDTO.setBlueInvoiceCode(invoiceInfoDO.getInvoiceCode());
        redOrderDTO.setBlueInvoiceNumber(invoiceInfoDO.getInvoiceNo());
        redOrderDTO.setSellerTaxNo(sellerInfoDO.getSellerCreditCode());
        redOrderDTO.setSellerName(sellerInfoDO.getSellerName());
        redOrderDTO.setBuyerTaxNo(invoiceInfoDO.getCustomerCreditCode());
        redOrderDTO.setBuyerName(invoiceInfoDO.getCustomerName());
        redOrderDTO.setRedReason("3");
        redOrderDTO.setAutoInvoice("1");
        redOrderDTO.setOrderNo(reversalInvoiceInfo.getInvoiceReversalId().toString());
        redOrderDTO.setCallbackUrl(invoiceNuonuoConfig.getCallbackUrl());

        String acceptOrderNo = reversalInvoiceInfo.getAcceptOrderNos();

        ElgLogger.info(log, l -> l.info("acceptOrderNo={} >> 发票冲红开票请求报文：{}", acceptOrderNo, JSONObject.toJSONString(redOrderDTO)));
        // 唯一标识，32位随机码，无需修改，保持默认即可
        String senid = IdGenerate.get32UUID();
        String result = sdk.sendPostSyncRequest(invoiceNuonuoConfig.getRequestUrl(), senid,
                invoiceNuonuoConfig.getAppKey(), invoiceNuonuoConfig.getAppSecret(),
                sellerInfoDO.getToken(), reversalInvoiceInfo.getSellerCreditCode(), method, JSONObject.toJSONString(redOrderDTO));

        ElgLogger.info(log, l -> l.info("acceptOrderNo={} << 发票冲红开票请求受理结果：{}", acceptOrderNo, result));
        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.containsKey("code")) {
            String code = resultJson.getString("code");
            String describe = resultJson.getString("describe");
            if (ReturnCode.E0000.name().equals(code)) {
                String invoiceSerialNum = resultJson.getString("result");
                reversalInvoiceInfo.setStatus(InvoiceStatusEnum.PROSESS.getValue());
                reversalInvoiceInfo.setSerialNo(invoiceSerialNum);
                reversalInvoiceInfo.setInvoiceMode(1);

                invoiceInfoService.insert(reversalInvoiceInfo);
                InvoiceInfoDO updateInvoiceInfo = InvoiceInfoDO.builder().id(invoiceInfoDO.getId())
                        .invoiceReversalFlag(InvoiceReversalFlag.PROCESSING.getFlag()).invoiceReversalId(reversalInvoiceInfo.getId()).build();
                invoiceInfoService.updateById(updateInvoiceInfo);
            } else  if(!"040102".equals(code)){
                //异常
                ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 发票冲红开票请求受理失败[{}:{}]", acceptOrderNo, code, describe));
                throw new RuntimeException(String.format("发票冲红开票受理失败[%s,%s]", code, describe));
            }
        } else {
            //异常
            ElgLogger.error(log, l -> l.error("acceptOrderNo={} << 发票冲红开票请求处理失败：响应报文不存在code字段", acceptOrderNo));
            throw new RuntimeException(String.format("发票冲红开票受理失败：响应报文不存在code字段"));
        }
    }

    public void invoiceResultNotify(String acceptOrderNo){
        CompletableFuture.runAsync(() -> {
            try {
                CenterNoEnum centerNoEnum = exchangeCenterService.getCenterNoEnumByAcceptOrderNo(acceptOrderNo);
                CenterInterfaceService cService = CenterInterfaceServiceFactory.getByCenterNoEnum(centerNoEnum);
                InnerBaseResp innerBaseResp = cService.invoiceResultNotify(acceptOrderNo);
                if (innerBaseResp != null && innerBaseResp.getRespCode().isSuccess()) {
                    ElgLogger.info(log, log -> log.info("受理订单号[{}] << 同步开票结果通知：响应报文：{}", acceptOrderNo, JSON.toJSONString(innerBaseResp)));
                } else {
                    ElgLogger.error(log, log -> log.error("受理订单号[{}] << 同步开票结果通知失败,待人工下次通知：响应报文：{}", acceptOrderNo, JSON.toJSONString(innerBaseResp)));
                }
            } catch (Exception e) {
                ElgLogger.error(log, log -> log.error("受理订单号[{}] << 同步开票结果通知异常：{}", acceptOrderNo, e.getMessage(), e));
            }
        });
    }
}
